<template>
  <div class="">
    <div id="container">
      <h1 id="title">我是标题</h1>
      <div class="symble">ppp</div>
      <p class="symble">ppp</p>
      <span class="symble">ppp</span>
      <div class="layer">测试分层效果</div>
    </div>
  </div>
</template>

<script setup lang="ts">
  import { reactive, onMounted, nextTick } from 'vue'

  // 在id是title节点 后面 添加一份有内容的<span>节点
  function addDom() {
    let container = document.getElementById('container')
    let targetSpan = document.createElement('span')
    targetSpan.innerHTML = '我是span节点'
    container?.appendChild(targetSpan)
    let selectClass = document.querySelectorAll('.symble')
    console.log(selectClass, 'selectClass')
  }
  // 移除dom
  function removeDom() {
    let container = document.getElementById('container')
    let titledom: HTMLElement | null = document.getElementById('title')
    if (container && titledom) {
      container.removeChild(titledom)
    }
  }
  nextTick(() => {
    addDom()
    setTimeout(() => {
      removeDom()
    }, 1000)
  })

  // ======================================= 分割线 =======================================

  interface SelfInfo {
    name: string
    age: number
  }

  let info = reactive<SelfInfo>({
    name: '铁锤',
    age: 18
  })

  // ======================================= 分割线 找出数组中两个相同的数 =======================================

  let array = [1, 2, 5, 4, 7, 9, 2, 4, 4]

  // 找出数组中两个相同的数
  // 排序法
  // 先对数组进行排序，然后检查相邻的元素是否相等。时间复杂度取决于排序算法的性能，一般为 O(n log n)。
  function testArr1(arr: any[]) {
    let result = [] as number[]
    arr.sort()
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] === arr[i + 1]) {
        result.push(arr[i])
      }
    }
    return Array.from(new Set(result))
  }
  const result1 = testArr1(array)
  console.log(result1, 'result1')

  // obj[key]值默认置为1，如果obj有重复的key，value值+1
  // 如果obj[key]>1,说明有重复数据，push进新数组
  // 对象法
  function testArr2(arr: any[]) {
    let obj = {}
    let newArr: number[] = []

    for (let i = 0; i < arr.length; i++) {
      const num = arr[i]
      if (obj[num] && obj[num] == 1) {
        newArr.push(num)
        obj[num]++
      } else if (obj[num] > 1) {
        obj[num]++
      } else {
        obj[num] = 1
      }
    }
    return newArr
    // return Array.from(new Set(newArr))
    console.log(obj, 'obj')
    console.log(newArr, 'newArr')
  }
  const result2 = testArr2(array)
  console.log(result2, 'result2')

  // 集合法
  function testArr3(arr: any[]) {
    let newArr = [] as any[]
    let set = new Set()

    for (let num of arr) {
      if (set.has(num) && !newArr.includes(num)) {
        newArr.push(num)
      } else {
        set.add(num)
      }
    }
    console.log(set, 'set')
    return newArr
  }
  const result3 = testArr3(array)
  console.log(result3, 'result3')

  // ======================================= 分割线 数组求和 =======================================

  // 数组求和
  function reduceAccount(arr: number[]) {
    let total = arr.reduce((total, i) => total + i, 0)
    return total
  }
  console.log(reduceAccount([1, 2, 3, 4, 5, 6, 7]), '数组求和')

  //嵌套数组求和
  function reduceAccoun2(arr: any[]) {
    let accout = arr
      .toString()
      .split(',')
      .reduce((total, i) => {
        return total + Number(i) // 没写return的话打印会是undefined
      }, 0)
    console.log(accout, 'accout')
    return accout
  }
  console.log(reduceAccoun2([1, 2, 3, [[4, 5], 6], 7, 8, 9]), 'reduceAccoun2')

  //嵌套数组求和递归遍历
  function reduceAccoun3(arr: any[]) {
    let total = 0
    for (let i = 0; i < arr.length; i++) {
      if (Array.isArray(arr[i])) {
        total += reduceAccoun3(arr[i])
      } else {
        total += arr[i]
      }
    }
    return total
  }
  console.log(reduceAccoun3([1, 2, 3, [[4, 5], 6], 7, 8, 9]), 'reduceAccoun3')

  // ======================================= 分割线 数组扁平化 =======================================

  // 数组扁平化 - flat
  let flatArr = [1, 2, 3, [[4, 5], 6], 7, 8, 9]
  function flatFun1(arr: any[]) {
    return arr.flat(Infinity)
  }
  console.log(flatFun1(flatArr), 'flatFun1')

  // 数组扁平化 - 递归遍历
  function flatFun2(arr: any[]) {
    let result: number[] = []
    for (let i = 0; i < arr.length; i++) {
      if (Array.isArray(arr[i])) {
        result = result.concat(flatFun2(arr[i]))
      } else {
        result.push(arr[i])
      }
    }
    return result
  }
  console.log(flatFun2(flatArr), 'flatFun2')

  // 数组扁平化 - reduce遍历
  function flatFun3(arr: any[]): number[] {
    return arr.reduce((prev, i) => {
      return prev.concat(Array.isArray(i) ? flatFun3(i) : i)
    }, [])
  }
  console.log(flatFun3(flatArr), 'flatFun3')

  // 数组扁平化 - toString+split(',')
  function flatFun4(arr: any[]): any[] {
    return arr.toString().split(',')
  }
  console.log(flatFun4(flatArr), 'flatFun4')

  // 扩展运算符
  function flatFun5(arr: any[]): any[] {
    // 只要有一个元素有数组，那么循环继续
    while (arr.some(Array.isArray)) {
      arr = [].concat(...arr)
    }
    return arr
  }
  console.log(flatFun5(flatArr), 'flatFun5')
  // ======================================= 分割线 for...of 遍历数组=======================================

  // for...of遍历普通对象会报错  适用于遍历数组、字符串、set、map等
  let forObject = Array.from({ 0: 'one', 1: 'two', 2: 'three', length: 3 })
  // let forObject = 'abcd'
  // let forObject = { name: '铁锤', age: 18 }  //报错
  for (let item of forObject) {
    console.log(item, 'item')
  }

  // ======================================= 分割线 如何获取两个数组之间不同的元素=======================================

  let arr1 = [1, 5, 6, 8, 7, 7, 4, 2, 10]
  let arr2 = [0, 15, 6, 18, 7, 27, 4, 22, 20]

  // 这种方法实际上不行，没有办法找出arr2中有的arr1中没有的
  function getDifferenceFrom1(arr1: any[], arr2: any[]) {
    let newArr2 = [...new Set(arr2)]
    let diff = arr1.filter(item => {
      return !newArr2.includes(item)
    })
    return diff
  }
  console.log(getDifferenceFrom1(arr1, arr2), 'diff1')

  // 这种可以实现
  function getDifferenceFrom2(arr1: any[], arr2: any[]) {
    let arr = [...arr1, ...arr2]
    const newArr = arr.filter(item => {
      return !(arr1.includes(item) && arr2.includes(item))
    })
    return newArr
  }
  console.log(getDifferenceFrom2(arr1, arr2), 'diff2')

  // ======================================= reduce方法的使用 分割线 =======================================

  // 累加
  const reduceArr1 = [1, 2, 3, 4].reduce((pre, cur) => {
    return pre + cur
  }, 0)
  console.log(reduceArr1, 'reduceArr1')

  // 找最大值 - 在每次调用回调函数时，我们比较累加器和当前值的大小，然后返回较大的那个值作为下一次调用的累加器值。
  // 这样，经过整个数组的遍历，累加器中就会包含数组中的最大值。
  const reduceArr2 = [1, 2, 3, 4].reduce((pre, cur) => {
    return Math.max(pre, cur)
  })
  console.log(reduceArr2, 'reduceArr2')

  // 去重 - 类型断言
  const reduceArr3 = [1, 1, 2, 3, 4, 4, 5, 6].reduce((preList, cur) => {
    if (!preList.includes(cur)) {
      preList.push(cur)
    }
    return preList
  }, [] as number[])
  console.log(reduceArr3, 'reduceArr3')

  // 数组反转 - 使用泛型指定类型
  const reduceArr4 = [1, 2, 3, 4, 5].reduce<number[]>((preList, cur) => {
    preList.unshift(cur)
    return preList
  }, [])
  console.log(reduceArr4, 'reduceArr4')

  // 字符串反转 - reverse方法
  const reduceStr1 = 'ABCD'
  console.log(reduceStr1.split('').reverse().join(''), 'reduceStr')

  // 字符串反转 - reduce方法
  const resultReduceStr2 = Array.from(reduceStr1).reduce((pre, cur) => {
    return `${cur}${pre}`
  }, '')
  console.log(resultReduceStr2, 'resultReduceStr2')

  // ======================================= 原地打乱一个数组 分割线 =======================================
  const shuffleArr = [1, 2, 3, 4, 5]
  function shuffle<T>(arr: Array<T>) {
    for (let i = 0; i < arr.length; i++) {
      const randomIndex: any = Math.floor(Math.random() * (arr.length - i) + i)
      ;[arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]]
    }
    return arr
  }
  console.log(shuffle<number>(shuffleArr), '打乱数组')

  onMounted(() => {})
</script>

<style lang="less" scoped>
  .layer {
    opacity: 0.2;
    width: 200px;
    height: 200px;
    background-color: aquamarine;
    position: fixed;
  }
</style>
